package com.agent.coreservice;

import java.awt.Component;

import com.agent.diagnostic.AbtTrace;


/**
 * this class links to dynamic link library and invoke some methods from it
 * this class was used as singleton pattern 
 * @author huy.tran
 *
 *NOTICE: 	This class is register full namespace with the DLL library. 
 *			So this should not change the package name when modifies it.
 */
public class JniHandler{
	
	final static private String LIB_NAME_LINUX_32	= "libTAJNIAgentLib.so";   //"TAJNIAgentLib.so";
	final static private String LIB_NAME_LINUX_64	= "libTAJNIAgentLib64.so"; //"TAJNIAgentLib64.so";
	final static private String LIB_NAME_W32	= "TAJavaAgentLib.dll";
	final static private String LIB_NAME_W64	= "TAJavaAgentLib64.dll";
	
	final static String installDir = "D:\\";
	
	//unique instance
	static private JniHandler theHandler = null;
	
	boolean bInitialized=false;
	/**
	 * constructor
	 */
	public JniHandler(){
		// 5/7/2013 [Hieu Dang][CDP-486]CLONE - Cannot launch TA Client on the test machine that is installed the Java version 1.7
		// Root cause : After set Environment Variables (path=C:\Program Files\Java\jre7\bin;...), 
		// 				TA runs via build-in JRE (ver 1.6), but agent runs via JRE ver 1.7. Then TA does not work. It means Java App (TA) and Agent do not run in the same JVM.
		// Solution : waiting for window show ("getHandleWindow"), we will initialize java agent (load library "jawt")
		// Affect area : start java agent
		//initialize();
	}
	
	private synchronized boolean initialize(){
		
				if(bInitialized ){
					return bInitialized;
				}
				
				bInitialized=true;
				
				//load jni lib
				if(Configuration.isWindows()){
					System.out.println("=========IS WINDOW =======");
					if(!loadLibraryForWin(LIB_NAME_W64) ){
						System.out.println("=========can not load with x64 =======");
						System.out.println("alsdkjflsdkajflkdsjlakfjdlsajlfjdlksaflsd===============");
						bInitialized=loadLibraryForWin("TAJavaAgentLib");
						System.out.println("=========load with x32: =======" + bInitialized);
						AbtTrace.info("Load jni lib WinW32");
					}
					
				}
				System.out.println("===== is load:  " + bInitialized);
				return bInitialized;
			}
	
	/** 
	 * load jni lib on Win OS
	 */
	boolean loadLibraryForWin(String nameLib){
		String sLibPath = installDir + nameLib;
		System.out.println("lib path: "+ sLibPath);
		return loadLibrary(installDir + nameLib);
//		if (!loadLibrary(sLibPath)) {
//			//try to load lib at default installation
//			sLibPath = installDir + nameLib;
//			// In the case : can not get Installdir from registry, we get the path to "/ext/" by using 
//			// location of TAJavaLoader/Agent.
//			if(!loadLibrary(sLibPath))
//				return loadLibrary(installDir + nameLib);;
//		}
//		
//		return true;
		
	}
	
	/**
	 * get unique instance
	 * @return
	 */
	static public JniHandler getInstance(){
		
		if(JniHandler.theHandler == null)
			JniHandler.theHandler = new JniHandler();
			
		return JniHandler.theHandler;
	}
	
	//announce the handler loading is successful
	private boolean success= false;
	
	/**
	 * check whether the dynamic link library was loaded successfully or not
	 * @return
	 */
	private boolean	isLoaded(){
		return initialize();
	}
	
	
	/**
	 * load dynamic link library to call native function later
	 * @param filePath	: path of library
	 * @return true if loading successfully, else false, log error
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	private boolean loadLibrary(String fileName){
		// Does not load 64bits library on 32bits system
		String arch = System.getProperty("os.arch");
		if (arch.equals("x86") && fileName.contains(LIB_NAME_W64)) {
			return false;
		}
		
		// 2010/11/22 Huy Tran & Huan Dong fixed bug TG #754 : Interface Viewer can not detects any controls on TA Client
		// TAClient uses JNI functions to create Java process so JavaAgent could not find JAWT.dll 
		// We have to explicitly load JAWT.DLL
//	    java.security.AccessController.doPrivileged(
//	        new java.security.PrivilegedAction() {
//		    public Object run() {
//		 
//		    	try
//				{
//		    		// this tip for load awt.dll in 64bits JVM
//					// hieu dang comment
//		    		//Toolkit.getDefaultToolkit();
//		    		
//					System.loadLibrary("jawt");
//				}
//				catch (UnsatisfiedLinkError ule){ 
//					// The file does not exist, or one of its dependent libraries could not be found
//					AbtTrace.error("[JniHandler]The File: JAWT.DLL does not exist! Error message : " + ule.getMessage() );
//				}
//				catch(Exception ex) { // Handle other exceptions ...
//					AbtTrace.error("[JniHandler]Loading library JAWT.DLL is fail by reason :{" + ex.getMessage()+"}" );			
//				}
//		    	
//				return null;
//			
//		    }
//		});	

		String filePath= fileName;
		try{

			// The System.load method is more straightforward 
			// and allows you to specify the filepath of the native library directly.
			//System.loadLibrary(filePath);
		
			//System.out.println("=======load lib BEFORE  ==========");
			try{
				System.out.println("======= Loading lib ====   BEFORE ==========");
				System.load(filePath);//loadLibrary(filePath);
				System.out.println("======= Loading lib ====   AFTER ==========");
			}
			catch(NullPointerException ex) {
				System.out.println("======= NullPointerException when loading lib ====   " + ex.toString());
			}
			catch(Exception e){
				System.out.println("======= Exception when loading lib ====   BEFORE ==========");
				e.printStackTrace();
				System.out.println("======= Exception when loading lib ====   AFTER ==========");
			}
			System.out.println("=======load lib success!!!!!!!!!!!!!!==========");
			//log file
			AbtTrace.info("[JniHandler][LoadLibrary]Loading file: ["+filePath + "] is successful!");
			success = true;
		}catch (SecurityException se){
			//log file
			AbtTrace.error("[JniHandler][LoadLibrary]Loading file: ["+filePath + "] is fail by Security Limit! {"+ se.getMessage()+ "}");
			success=false;
		}catch (NullPointerException ne){ 
			AbtTrace.error("[JniHandler][LoadLibrary]Loading file: ["+filePath + "] is fail by null path");
			success=false;
		}catch (UnsatisfiedLinkError ule){
			//the file does not exist.
			AbtTrace.error("[JniHandler][LoadLibrary]The File: ["+filePath + "] does not exist!");
			AbtTrace.error(ule.getMessage());
			success=false;
		}
		catch(Exception ex) {
			System.out.println("======= Exception when loading lib ====   " + ex.toString());
			AbtTrace.error("[JniHandler][LoadLibrary]Loading library is fail by reason :{" + ex.getMessage()+"}" );
			success=false;
		}
	
		return success;
	}
	
	/**
	 * get OS ID of component
	 * for each OS, OSID was defined differently, such as HANDLE for WINDOW OS etc...
	 * @param component	this is a component on GUI
	 * @return	ID
	 */
	private native int getNativeID(Component component);
	
	/**
	 * get handle of component
	 * @param component
	 * @return	0: if the library is not loaded
	 * 			handle window
	 */
	public int getHandleWindow(Component component){
		
		AbtTrace.warningIf(component == null, "[JniHandler][GetHandleWindow]Component = null");
			
		int navativeID = 0;
		
		// if library was loaded
		// call get native ID from jni
		if(isLoaded()){			
			try {
				navativeID = getNativeID(component);
			} catch (Exception e) {
				AbtTrace.error("[JniHandler][GetHandleWindow]getNavetiveID Exception: " + e.getMessage());
			}
		}
		return navativeID;
		
	}
}
